/* 
 * hkx2dae
 * The Havok 2 Collada Converter
 * http://code.google.com/p/hkx2dae/
 *
 * Author: Sam Edge (double.edged.software@gmail.com)
 */

// Base and Math
#include <Common/Base/hkBase.h>
#include <Common/Base/System/hkBaseSystem.h>
#include <Common/Base/Memory/hkThreadMemory.h>
#include <Common/Base/Memory/Memory/Pool/hkPoolMemory.h>
#include <Common/Base/System/Error/hkDefaultError.h>
#include <Common/Base/Monitor/hkMonitorStream.h>

// Keycode
#include <Common/Base/keycode.cxx>

// Common Classes
#include <Common/SceneData/Scene/hkxScene.h>
#include <Common/SceneData/Mesh/hkxMesh.h>
#include <Common/SceneData/Mesh/hkxMeshSection.h>
#include <Common/SceneData/Mesh/hkxVertexBuffer.h>

// Serialize
#include <Common/Serialize/Util/hkStructureLayout.h>
#include <Common/Serialize/Util/hkRootLevelContainer.h>
#include <Common/Serialize/Util/hkSerializeUtil.h>
#include <Common/Serialize/Resource/hkResource.h>

// Classes, include all
#define INCLUDE_HAVOK_PHYSICS_CLASSES
#define INCLUDE_HAVOK_ANIMATION_CLASSES
#define HK_CLASSES_FILE <Common/Serialize/Classlist/hkClasses.h>
#include <Common/Serialize/Util/hkBuiltinTypeRegistry.cxx>

// Full Compatability
#define HK_COMPAT_FILE <Common/Compat/hkCompatVersions.h>
#include <Common/Compat/hkCompat_All.cxx>

// Std
#include <iostream>
#include <string>
#include <stack>
using std::cout;
using std::string;
using std::stack;

#include <hkx2dae.h>

// Havok Error Handling
#include <stdio.h>
static void HK_CALL errorReport(const char* msg, void*)
{
	printf("%s", msg);
}

static string getFileName(std::string fn)
{
	int pos = fn.find_last_of("\\") + 1;
	int ext = fn.find_last_of(".");
	int len = ext - pos;
	return fn.substr(pos, len);
}

int HK_CALL main(int argc, const char* argv[])
{
#if defined _DEBUG
	argc = 2;
	argv[1] = "d:\\agitator_skeleton.hkx";
#endif

	if (argc == 1) {
		cout << "Usage:\n"
				" -m   Export Mesh Libraries\n"
			    " -s   Export Skeleton Libraries\n"
				" -a   Export Animation Libraries\n"
				" -o <filename>   Output File Name\n";
		return 0;
	}

	bool mesh = false;
	bool skeleton = false;
	bool animation = false;
	stack<string> input;

	for (int i = 1; i < argc; i++) {
		if (string(argv[i]) == "-m")
			mesh = true;
		else if (string(argv[i]) == "-s")
			skeleton = true;
		else if (string(argv[i]) == "-a")
			animation = true;
		else
			input.push(string(argv[i]));
	}

	// if no args are set, export everything by default
	if (!mesh && !skeleton && !animation) {
		mesh = true;
		skeleton = true;
		animation = true;
	}

#if defined _DEBUG
	// Initialize Havok memory manager
	hkPoolMemory* memoryManager = new hkPoolMemory();
	hkThreadMemory* threadMemory = new hkThreadMemory(memoryManager);
	hkBaseSystem::init( memoryManager, threadMemory, errorReport );
	memoryManager->removeReference();

	// Initialize Stack
	char* stackBuffer;
	int stackSize = 0x100000;
	stackBuffer = hkAllocate<char>( stackSize, HK_MEMORY_CLASS_BASE);
	hkThreadMemory::getInstance().setStackArea( stackBuffer, stackSize);
#endif

	for (int i = 0; i < input.size(); i++) {
		// Initialize the Havok data sources
		hkResource* loaded_data = hkSerializeUtil::load(input.top().c_str());
		hkRootLevelContainer* container = loaded_data->getContents<hkRootLevelContainer>();
		HK_ASSERT2(0xa6451543, container != HK_NULL, "Could not load root level object." );
		hkxScene* scene = reinterpret_cast<hkxScene*>(container->findObjectByType("hkxScene"));
	
		// Declare the hkx2dae object
		hkx2dae* dae = new hkx2dae(getFileName(input.top()));

		// Run the conversions and save
		dae->addAsset(scene);
		if (mesh) dae->addLibraryGeometries(scene);
		if (skeleton) dae->addLibraryControllers(scene);
		//if (animation) dae->addLibraryAnimations(scene);
		dae->save();

		// Delete resources
		delete dae;
		delete scene;
		delete container;
		delete loaded_data;
	}

#if defined _DEBUG
	// Deallocate stack area
	threadMemory->setStackArea(0, 0);
	hkDeallocate(stackBuffer);
	threadMemory->removeReference();
	// Quit base system
	//hkBaseSystem::quit();
#endif

	return 0;
}
